package implementation1.app.commands;

import exceptions.CommandErrorFromUserException;
import exceptions.CommandException;
import exceptions.StreamEOFException;
import exceptions.StreamException;
import implementation1.app.Global;
import implementation1.app.streams.AccessAttributes;
import implementation1.app.streams.FileStream;
import implementation1.data.states.TerminatedStatus;
import interfaces.app.IProcess;
import interfaces.app.IStream;
import interfaces.data.IHandle;

import java.io.File;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

/**
 * Class for handle of command "sort" for sorting of input lines and writing them on output.
 * <p/>
 * Created: 22.10.11*
 *
 * @author Jan Svab
 */
public class Sort extends Command
{
    /**
     * TRUE - sorting reverse, FALSE default sorting
     */
    private boolean bSortReverse = false;

    /**
     * Contains path to file if it is one of commands parameters
     */
    private String pathToFile = null;

    /**
     * Default constructor.
     *
     * @param parent parent process over which is command processed
     * @param handle parameters of command
     */
    public Sort(IProcess parent, IHandle handle)
    {
        super(parent, handle);
    }

    /**
     * Main method for processing of command.
     *
     * @param args arguments of command
     */
    @Override
    public void mainCommand(String[] args) throws CommandException
    {
        if (handle.getOut() == null)
        {
            throw new CommandException(bundle.getString("error.outputStream.empty"));
        }

        analyzingArgs(args);

        IStream inStream = null;
        IStream outStream = handle.getOut();

        if (pathToFile == null)
        {
            inStream = handle.getIn();
        }
        else
        {
            //checking if file exist
            File file = Global.getFileWithAbsPath(handle.getActualPath(), pathToFile);

            if (!file.exists() || !file.isFile())
            {
                throw new CommandErrorFromUserException(bundle.getString("error.file.noExist"));
            }

            inStream = new FileStream(file.getAbsolutePath());
        }

        try
        {
            outStream.open(AccessAttributes.WRITE);
            openedStreamsOfProcess.add(outStream);
            inStream.open(AccessAttributes.READ);
            openedStreamsOfProcess.add(inStream);

            //reading of lines of file
            List<String> buffer = new ArrayList<String>();
            while (inStream.isOpen())
            {
                String s;
                try
                {
                    s = inStream.readLine();
                } catch (StreamEOFException e)
                {
                    break;  //end of stream
                }

                if (Thread.interrupted()) //in other process was created request on terminate this process
                {
                    status = new TerminatedStatus();
                    return;
                }

                if (hasEndStatus()) //thread should quit
                {
                    return;
                }

                buffer.add(s);
            }

            //sorting lines from file
            Collator collator = Collator.getInstance(Locale.getDefault());
            Collections.sort(buffer, collator);

            if (bSortReverse)
            {
                Collections.reverse(buffer);
            }

            for (String line : buffer)
            {
                if (Thread.interrupted()) //in other process was created request on terminate this process
                {
                    status = new TerminatedStatus();
                    return;
                }

                if (hasEndStatus()) //thread should quit
                {
                    return;
                }

                outStream.writeLine(line);
            }

        } catch (StreamException e)
        {
            throw new CommandException(e.getMessage());
        } finally
        {
            Global.closeStreamQuietly(inStream);
            Global.closeStreamQuietly(outStream);

            openedStreamsOfProcess.remove(inStream);
            openedStreamsOfProcess.remove(outStream);
        }
    }

    /**
     * Controls arguments of the command.
     *
     * @param args array with arguments
     * @throws CommandErrorFromUserException Thrown if occurs some error in arguments
     */
    private void analyzingArgs(String[] args) throws CommandErrorFromUserException
    {
        bSortReverse = false;
        pathToFile = null;

        if (args == null || args.length == 0)
        {
            return;
        }

        if (args.length == 1)
        {
            if (args[0].contains("-r"))
            {
                bSortReverse = true;
            }
            else
            {
                pathToFile = args[0];
            }

        }
        else if (args.length == 2)
        {
            if (args[0].contains("-r"))
            {
                bSortReverse = true;
                pathToFile = args[1];
            }
            else
            {
                throw new CommandErrorFromUserException(bundle.getString("error.sort.argError"));
            }
        }
        else
        {
            throw new CommandErrorFromUserException(bundle.getString("error.arguments.wrongCount"));
        }

    }

    @Override
    public String toString()
    {
        return "sort";
    }
}
